package org.jiucheng.magpiebridge.server.aio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import org.jiucheng.magpiebridge.server.aio.proxy.ProxyAttachment;
import org.jiucheng.magpiebridge.server.util.Container;

/**
 * 
 * @author jiucheng
 *
 */
public class ServerAttachment {
    // 代理服务
    private List<AsynchronousServerSocketChannel> asynchronousServerSocketChannels = new ArrayList<AsynchronousServerSocketChannel>();
    // 代理连接
    public static final ConcurrentMap<Integer, ProxyAttachment> proxys = new ConcurrentHashMap<Integer, ProxyAttachment>();
    
    // Client连接
    AsynchronousSocketChannel server;
    // Client读入数据
    ByteBuffer readBuffer;
    // Client写入数据
    ByteBuffer writeBuffer;
    // 当前在写
    public final AtomicBoolean writed = new AtomicBoolean(false);
    
    private ProxyAttachment proxyAttachment;
    private boolean mastered;
    
	private List<String> domains;
    
    public ServerAttachment(AsynchronousSocketChannel server) {
        this.server = server;
    }
    
    public List<String> getDomains() {
		return domains;
	}
    
    public void setDomains(List<String> domains) {
		this.domains = domains;
	}
    
    public void addDomain(String domain) {
    	if (domain != null && !domain.isEmpty()) {
        	if (domains == null) {
        		domains = new ArrayList<String>();
        	}
        	domains.add(domain);
    	}
    }
    
    public boolean isMastered() {
		return mastered;
	}
    
    public ServerAttachment setMastered(boolean mastered) {
		this.mastered = mastered;
		return this;
	}
    
    public ProxyAttachment getProxyAttachment() {
		return proxyAttachment;
	}
    
    public ServerAttachment setProxyAttachment(ProxyAttachment proxyAttachment) {
		this.proxyAttachment = proxyAttachment;
		return this;
	}
    
    public ByteBuffer getWriteBuffer() {
		return writeBuffer;
	}
    
    public ServerAttachment setWriteBuffer(ByteBuffer writeBuffer) {
		this.writeBuffer = writeBuffer;
		return this;
	}
    
    public ByteBuffer getReadBuffer() {
        return readBuffer;
    }
    
    public ServerAttachment setReadBuffer(ByteBuffer readBuffer) {
        this.readBuffer = readBuffer;
        return this;
    }
    
    public AsynchronousSocketChannel getServer() {
        return server;
    }

    public void putProxy(Integer uri, ProxyAttachment proxy) {
        proxys.put(uri, proxy);
    }
    
    public ProxyAttachment getProxy(Integer uri) {
        return proxys.get(uri);
    }
    
    public ProxyAttachment removeProxy(Integer uri) {
        return proxys.remove(uri);
    }
    
    public void addProxyServer(AsynchronousServerSocketChannel asynchronousServerSocketChannel) {
        asynchronousServerSocketChannels.add(asynchronousServerSocketChannel);
    }
    
    public void close() {
        if (server != null) {
            try {
                server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    	if (mastered) {
    		if (domains != null && domains.isEmpty()) {
    			for (String domain : domains) {
    				Container.DOMAINS.remove(domain);
    			}
    		}
            for (AsynchronousServerSocketChannel asynchronousServerSocketChannel : asynchronousServerSocketChannels) {
                if (asynchronousServerSocketChannel != null) {
                    try {
                        asynchronousServerSocketChannel.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
    	} else {
    		if (proxyAttachment != null && proxyAttachment.canWrited()) {
    			proxyAttachment.close();
    		}
    	}
    }
    
    public void clear() {
        if (mastered) {
            if (domains != null && domains.isEmpty()) {
                for (String domain : domains) {
                    Container.DOMAINS.remove(domain);
                }
                domains.clear();
            }
            for (AsynchronousServerSocketChannel asynchronousServerSocketChannel : asynchronousServerSocketChannels) {
                if (asynchronousServerSocketChannel != null) {
                    try {
                        asynchronousServerSocketChannel.close();
                    } catch (Exception e) {
                        // e.printStackTrace();
                    }
                }
            }
            asynchronousServerSocketChannels.clear();
        }
    }
    
	public boolean canWrited() {
        while (!writed.compareAndSet(false, true)) {
        	try {
				TimeUnit.MILLISECONDS.sleep(50L);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
        }
        return true;
	}
}
